package com.wzdigit.wms.wms.service.inv;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.wzdigit.framework.Shift;
import com.wzdigit.mes.basic.api.BasicSimpleCodeRuleApi;
import com.wzdigit.wms.basic.client.Pager;
import com.wzdigit.wms.basic.client.PagerInfo;
import com.wzdigit.wms.basic.client.request.inv.SealGoodsRequest;
import com.wzdigit.wms.basic.client.request.inv.SearchQualifiedGoodsRequest;
import com.wzdigit.wms.basic.client.request.inv.SearchSealGoodsGroupRequest;
import com.wzdigit.wms.basic.client.response.Result;
import com.wzdigit.wms.basic.client.response.inv.QualifiedGoodsResponse;
import com.wzdigit.wms.basic.client.response.inv.SealGoodsGroupResponse;
import com.wzdigit.wms.basic.domain.basic.Sku;
import com.wzdigit.wms.basic.domain.dtos.inventory.UpdateInventoryInputDto;
import com.wzdigit.wms.basic.domain.inv.SealDtl;
import com.wzdigit.wms.basic.domain.inv.SealDtlGoods;
import com.wzdigit.wms.basic.domain.inv.SealHeader;
import com.wzdigit.wms.basic.domain.inventory.Lotno;
import com.wzdigit.wms.basic.enums.QaStatusEnum;
import com.wzdigit.wms.basic.enums.SealFlagEnum;
import com.wzdigit.wms.basic.enums.SealTypeEnum;
import com.wzdigit.wms.basic.mapper.core.basic.SkuMapper;
import com.wzdigit.wms.basic.mapper.core.inv.SealDtlGoodsMapper;
import com.wzdigit.wms.basic.mapper.core.inv.SealDtlMapper;
import com.wzdigit.wms.basic.mapper.core.inv.SealHeaderMapper;
import com.wzdigit.wms.basic.mapper.core.inventory.GoodsMapper;
import com.wzdigit.wms.basic.util.HttpSessionUtil;
import com.wzdigit.wms.basic.service.code.InventoryService;
import com.wzdigit.wms.basic.service.code.LotnoService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 封库-服务类
 * @author yangdongjie
 * @GdnService.java
 * @2021年2月24日下午3:25:03
 */
@Service
@Slf4j
public class SealGoodsService {
	
	@Autowired
	private SkuMapper skuMapper;

	@Autowired
	private GoodsMapper goodsMapper;
	
	@Autowired
	private SealDtlMapper sealDtlMapper;
	
	@Autowired
	private SealHeaderMapper sealHeaderMapper;
	
	@Autowired
	private SealDtlGoodsMapper sealDtlGoodsMapper;
	
	@Autowired
	private LotnoService lotnoService;
	
	@Autowired
	private InventoryService inventoryService;
	
	@Reference(version = "${dubbo.consumers.basic.simple.code.rule.api:1.0.0}", check = false)
	private BasicSimpleCodeRuleApi basicSimpleCodeRuleApi;
	
	/**
	 * 【封库主档数据】输出
	 * @param dto
	 * @param pager
	 * @return
	 */
	public PagerInfo<List<SealGoodsGroupResponse>> searchSealGoodsGroup(SearchSealGoodsGroupRequest dto, Pager<?> pager) {
    	Page<?> page = PageHelper.offsetPage(pager.getSkipCount(), pager.getMaxResultCount());
        PagerInfo<List<SealGoodsGroupResponse>> pagerInfo = new PagerInfo<>();
        
        List<SealGoodsGroupResponse> list = goodsMapper.selectSealGoodsGroup(dto);
        pagerInfo.setTotalCount(page.getTotal());
        pagerInfo.setItems(list);
		return pagerInfo;
    }
	
	/**
	 * 【封库合格SN数据】输出
	 * @param dto
	 * @param pager
	 * @return
	 */
	public PagerInfo<List<QualifiedGoodsResponse>> searchQualifiedGoods(SearchQualifiedGoodsRequest dto, Pager<?> pager) {
    	Page<?> page = PageHelper.offsetPage(pager.getSkipCount(), pager.getMaxResultCount());
        PagerInfo<List<QualifiedGoodsResponse>> pagerInfo = new PagerInfo<List<QualifiedGoodsResponse>>();
        
        List<QualifiedGoodsResponse> list = goodsMapper.selectQualifiedGoods(dto, QaStatusEnum.OK.code, null);
        pagerInfo.setTotalCount(page.getTotal());
        pagerInfo.setItems(list);
		return pagerInfo;
    }
	
	/**
	 * 封库
	 * 
	 * @param dto
	 * @param servletRequest
	 * @return
	 * @throws IllegalAccessException 
	 * @throws IllegalArgumentException 
	 */
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
	public synchronized Result<String> sealGoods(SealGoodsRequest dto, HttpServletRequest servletRequest) throws Exception {
		// 检验1
		List<SearchQualifiedGoodsRequest> items = dto.getItems();
		int size = items.stream().collect(Collectors.groupingBy(t -> (t.getFactory() + "#" + t.getOwner()), Collectors.toList())).size();
		if(size > 1) {
			Shift.fatal("勾选的封库信息，必须都相同“组织”，“货主”才允许生成封库单！");
		}
		
		// 检验2
		size = 0;
		List<List<QualifiedGoodsResponse>> list = new ArrayList<>();
		for (SearchQualifiedGoodsRequest item : items) {
			item.setStatus(-5710);
			List<QualifiedGoodsResponse> qualifiedGoodsList = goodsMapper.selectQualifiedGoods(item, QaStatusEnum.OK.code, null);
			size += qualifiedGoodsList.size();
			list.add(qualifiedGoodsList);
		}
		if(size == 0) {
			Shift.fatal("没有可封库数据！");
		}
		
		String loginName = HttpSessionUtil.getLoginName(servletRequest);
		Date date = new Date();
		
		List<QualifiedGoodsResponse> goodsItemList = new ArrayList<>(size);
		List<Integer> goodsIdList = new ArrayList<>(size);
		
		Class<SealDtl> sealDtlClass = SealDtl.class;
		Class<Lotno> lotnoClass = Lotno.class;
		
		// 封库单单据号
		String simpleCodeRule = "FK";
		String sealNo = basicSimpleCodeRuleApi.GenerateCode(simpleCodeRule);
		
		// 封库单表头
		SealHeader sealHeader = new SealHeader();
		sealHeader.setSealNo(sealNo);
		sealHeader.setSealType(SealTypeEnum.SEAL.code);
		sealHeader.setFactory(items.get(0).getFactory());
		sealHeader.setOwner(items.get(0).getOwner());
		sealHeader.setReason(dto.getReason());
		sealHeader.setSealTime(date);
		sealHeader.setSealUser(loginName);
		sealHeader.setCreateTime(date);
		sealHeader.setCreateUser(loginName);
		sealHeaderMapper.insert(sealHeader);
		
		// 封库单明细
		for (int i = 0; i < items.size(); i++) {
			List<QualifiedGoodsResponse> goodsList = list.get(i);
			if(goodsList.size() == 0) {
				continue;
			}
			
			// 封库单明细
			SearchQualifiedGoodsRequest item = items.get(i);
			Sku sku = skuMapper.selectById(item.getSkuId());
			
			SealDtl sealDtl = new SealDtl();
			sealDtl.setSealHeaderId(sealHeader.getSealHeaderId());
			sealDtl.setSealNo(sealNo);
			sealDtl.setSealLineNo(1 + i);
			sealDtl.setSkuId(item.getSkuId());
			sealDtl.setQaStatus(QaStatusEnum.NG.code);
			sealDtl.setLotno(item.getLotno());
			sealDtl.setSoNo(item.getSoNo());
			sealDtl.setSoLineNo(item.getSoItem());
			sealDtl.setPoNo(item.getPoNo());
			sealDtl.setPrdWo(item.getPrdWo());
			sealDtl.setWhsId(item.getWhsId());
			sealDtl.setZoneId(item.getZoneId());
			sealDtl.setInspNo(item.getInspNo());
			sealDtl.setCustomerModle(sku.getModel());
			sealDtl.setUnit(sku.getBaseUnit());
			sealDtl.setSealQty(new BigDecimal(goodsList.size()));
			sealDtl.setUnsealQty(BigDecimal.ZERO);
			sealDtl.setStatus(1);
			sealDtl.setCreateTime(date);
			sealDtl.setCreateUser(loginName);
			sealDtlMapper.insert(sealDtl);
			
			Lotno lotno = lotnoService.getLotnoBySealDtlId(sealDtl.getSealDtlId());
			if(lotno != null) {
				sealDtl.setLotno(lotno.getLotno());
				for (int j = 1; j < 13; j++) {
					Field lotnoField = lotnoClass.getDeclaredField("lotAttr" + j);
					lotnoField.setAccessible(true);
					Object lotnoFieldValue = lotnoField.get(lotno);
					
					Method setLotAttr = sealDtlClass.getMethod("setLotAttr" + j, String.class);
					setLotAttr.setAccessible(true);
					setLotAttr.invoke(sealDtl, lotnoFieldValue == null ? null : lotnoFieldValue.toString());
				}
				sealDtlMapper.updateById(sealDtl);
			}
			
			// 封库单明细SN
			for (QualifiedGoodsResponse goods : goodsList) {
				SealDtlGoods sealDtlGoods = new SealDtlGoods();
				sealDtlGoods.setSealDtlId(sealDtl.getSealDtlId());
				sealDtlGoods.setGoodsSn(goods.getGoodsSn());
				sealDtlGoods.setGoodsId(goods.getGoodsId());
				sealDtlGoods.setQty(goods.getQty());
				sealDtlGoods.setStatus(goods.getStatus());
				sealDtlGoods.setSealFlag(SealFlagEnum.SEAL.code);
				sealDtlGoods.setCreateTime(date);
				sealDtlGoods.setCreateUser(loginName);
				sealDtlGoodsMapper.insert(sealDtlGoods);
				
				goodsIdList.add(goods.getGoodsId());
				goodsItemList.add(goods);
			}
		}
		
		// 更新库存和sn状态
		Map<String, List<QualifiedGoodsResponse>> zoneIdInvMap = goodsItemList.stream().collect(
				Collectors.groupingBy(g -> (g.getWhsId() + "#" + g.getOwner() + "#" + g.getSkuId() + "#" + 
						g.getFactory() + "#" + g.getLotno() + "#" + g.getVendorId() + "#" + g.getInvAttr() + "#" + 
						g.getQaStatus() + "#" + g.getUnit() + "#" + g.getZoneId()), Collectors.toList()));
		Map<String, List<QualifiedGoodsResponse>> locIdInvMap = goodsItemList.stream().collect(
				Collectors.groupingBy(g -> (g.getWhsId() + "#" + g.getOwner() + "#" + g.getSkuId() + "#" + 
						g.getFactory() + "#" + g.getLotno() + "#" + g.getVendorId() + "#" + g.getInvAttr() + "#" + 
						g.getQaStatus() + "#" + g.getUnit() + "#" + g.getLocId()), Collectors.toList()));
		// 库区库存
		for (String zoneIdInvKey : zoneIdInvMap.keySet()) {
			List<QualifiedGoodsResponse> zoneIdInvList = zoneIdInvMap.get(zoneIdInvKey);
			QualifiedGoodsResponse zoneIdInv = zoneIdInvList.get(0);
			
			UpdateInventoryInputDto input = new UpdateInventoryInputDto();
			input.setWhsId(zoneIdInv.getWhsId());
			input.setOwner(zoneIdInv.getOwner());
			input.setSkuId(zoneIdInv.getSkuId());
			input.setFactory(zoneIdInv.getFactory());
			input.setLotNo(zoneIdInv.getLotno());
			input.setVendorId(zoneIdInv.getVendorId());
			input.setInvAttr(zoneIdInv.getInvAttr());
			input.setQaStatus(zoneIdInv.getQaStatus());
			input.setUnit(zoneIdInv.getUnit());
			input.setZoneId(zoneIdInv.getZoneId());
			input.setQty(new BigDecimal(zoneIdInvList.size()).negate());
			input.setOperator(loginName);
			// 减少合格的库存
			inventoryService.updateZoneInventory(input);
			
			input.setQaStatus(QaStatusEnum.NG.code);
			input.setQty(input.getQty().abs());
			// 增加不合格的库存
			inventoryService.updateZoneInventory(input);
		}
		
		// 库位库存
		for (String locIdInvKey : locIdInvMap.keySet()) {
			List<QualifiedGoodsResponse> locIdInvList = locIdInvMap.get(locIdInvKey);
			QualifiedGoodsResponse locIdInv = locIdInvList.get(0);
			
			UpdateInventoryInputDto input = new UpdateInventoryInputDto();
			input.setWhsId(locIdInv.getWhsId());
			input.setOwner(locIdInv.getOwner());
			input.setSkuId(locIdInv.getSkuId());
			input.setFactory(locIdInv.getFactory());
			input.setLotNo(locIdInv.getLotno());
			input.setVendorId(locIdInv.getVendorId());
			input.setInvAttr(locIdInv.getInvAttr());
			input.setQaStatus(locIdInv.getQaStatus());
			input.setUnit(locIdInv.getUnit());
			input.setLocId(locIdInv.getLocId());
			input.setQty(new BigDecimal(locIdInvList.size()).negate());
			input.setOperator(loginName);
			// 减少合格的库存
			inventoryService.updateLocInventroy(input);
			
			input.setQaStatus(QaStatusEnum.NG.code);
			input.setQty(input.getQty().abs());
			// 增加不合格的库存
			inventoryService.updateLocInventroy(input);
		}
		goodsMapper.batchUpdateQaStatus(QaStatusEnum.NG.code, loginName, goodsIdList);
//		throw new Exception(sealNo);
		//Shift.fatal("业务回滚");
		return new Result<String>(sealNo);
    }
}
